#include "LogFile.h"

LogFile::LogFile() {
#ifdef LOGENABLED
	this->name = this->getDefaultLogFile();
    this->fd = this->openLogFile();
    this->isDestroyed = false;
#endif
}

LogFile::LogFile(string fileName) {
#ifdef LOGENABLED
	this->name = fileName;
    this->fd = this->openLogFile();
    this->isDestroyed = false;
#endif
}

int LogFile::log(string message) {
#ifdef LOGENABLED
	if (this->isDestroyed) {
		throw string("Esta instancia de LogFile ya fue destruida.");
	}

	this->lock();

	string logMessage = getLogMessage(message);
	lseek(this->fd, 0, SEEK_END);
	int result = write(this->fd, logMessage.c_str(), logMessage.size());

	this->unlock();

	return result;
#else
	return 0;
#endif
}

int LogFile::openLogFile() {
#ifdef LOGENABLED
    this->fl.l_type = F_WRLCK;
    this->fl.l_whence = SEEK_SET;
    this->fl.l_start = 0;
    this->fl.l_len = 0;
    this->fl.l_pid = getpid();

    return open(this->name.c_str(), O_CREAT | O_WRONLY, 0644);
#else
	return 0;
#endif
}

string LogFile::getLogMessage(string message) {
#ifdef LOGENABLED
    time_t rawtime;
    struct tm *timeinfo;

    time(&rawtime);
    timeinfo = localtime(&rawtime);
    string time = asctime(timeinfo);
    time.erase(remove(time.begin(), time.end(), '\n'), time.end());

    stringstream stream;
    stream << "[" << time << "] [Process Id: " << getpid() << "] " << message << endl;

    return stream.str();
#else
	return "";
#endif
}

string LogFile::getDefaultLogFile() {
#ifdef LOGENABLED
    mkdir(ROOTDIRECTORY, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

    stringstream stream;
    stream << ROOTDIRECTORY << "log" << getpid() << ".txt";
    return stream.str();
#else
	return "";
#endif
}

int LogFile::lock() {
#ifdef LOGENABLED
	this->fl.l_type = F_WRLCK;
	int result = fcntl(this->fd, F_SETLKW, &(this->fl));
	return result;
#else
	return 0;
#endif
}

int LogFile::unlock() {
#ifdef LOGENABLED
	this->fl.l_type = F_UNLCK;
	int result = fcntl(this->fd, F_SETLK, &(this->fl));
	return result;
#else
	return 0;
#endif
}

void LogFile::destroy() {
#ifdef LOGENABLED
	if (!this->isDestroyed) {
		close(this->fd);
		this->isDestroyed = true;
	}
#endif
}

LogFile::~LogFile() {
#ifdef LOGENABLED
	this->destroy();
#endif
}
